using System;
using System.Collections.Generic;
using System.Linq;
#if XNA
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#else
using SilverArcade.SilverSprite;
using SilverArcade.SilverSprite.Graphics;
using SilverArcade.SilverSprite.Content;
using SilverArcade.SilverSprite.Input;
#endif
using System.IO;
using System.Globalization;

namespace CakeAnimation
{
    public class AnimationSerializer
    {
        public void SaveAnimation(Animation anim, string name)
        {
            TextWriter tw = new StreamWriter(name);
            foreach (var item in anim.m_Keyframes)
            {
                SaveKeyframe(item, tw);
            }

            tw.Close();
        }

        private void SaveKeyframe(KeyFrame kf, TextWriter tw)
        {
            tw.WriteLine("Keyframe=" + kf.Time.ToString(CultureInfo.InvariantCulture));
            SaveSkeleton(kf.Pose, tw);
        }

        public void Save(Skeleton skeleton, string name)
        {
            TextWriter tw = new StreamWriter("skel" + name + ".txt");
            SaveSkeleton(skeleton, tw);

            // close the stream
            tw.Close();
        }

        private void SaveSkeleton(Skeleton skeleton, TextWriter tw)
        {
            tw.WriteLine("Root=" + skeleton.RootBone.Position.X.ToString(CultureInfo.InvariantCulture) + " " + skeleton.RootBone.Position.Y.ToString(CultureInfo.InvariantCulture));
            WriteBone(tw, skeleton.RootBone);
        }

        private void WriteBone(TextWriter tw, Bone bone)
        {
            tw.WriteLine(bone.Name + "=" + bone.LocalRotation.ToString(CultureInfo.InvariantCulture));

            foreach (var item in bone.Children)
            {
                WriteBone(tw, item);
            }
        }


        public Animation LoadAnimation(AnimationContext context, string name, Stream stream, Skeleton skeletonTemplate)
        {
            List<KeyFrame> kfs = new List<KeyFrame>();

            TextReader tr = new StreamReader(stream );
            string line;
            while ((line = tr.ReadLine()) != null)
            {
                if (line.Contains("Keyframe="))
                {
                    float time = float.Parse(line.Split('=')[1], CultureInfo.InvariantCulture);
                    KeyFrame kf = new KeyFrame(context, time, skeletonTemplate);
                    kfs.Add(kf);
                }
                else if (line.Contains("Root="))
                {
                    Vector2 position = ParseVector2(line.Split('=')[1]);

                    Skeleton s = skeletonTemplate.Clone();
                    s.RootBone.LocalPosition = position;
                    kfs[kfs.Count - 1].Pose = s;
                }
                else
                {
                    Skeleton s = kfs[kfs.Count - 1].Pose;
                    string bone = line.Split('=')[0];
                    float rot = float.Parse(line.Split('=')[1], CultureInfo.InvariantCulture);
                    Bone b = s.GetBone(bone);
                    b.LocalRotation = rot;
                }
            }

            tr.Close();

            Animation anim = new Animation(System.IO.Path.GetFileNameWithoutExtension(name), kfs);

            foreach (KeyFrame kf in anim.m_Keyframes)
            {
                kf.Pose.RootBone.UpdateTransform();
            }

            return anim;
        }


        public Skeleton Load(AnimationContext context, string name)
        {
            TextReader tr = new StreamReader("skel" + name + ".txt");

            Vector2 position = ParseVector2(tr.ReadLine().Split('=')[1]);

            Skeleton s = new Skeleton(context, "SkeletonRig.txt");
            s.RootBone.LocalPosition = position;

            string line;
            while ((line = tr.ReadLine()) != null)
            {
                string bone = line.Split('=')[0];
                float rot = float.Parse(line.Split('=')[1]);
                Bone b = s.GetBone(bone);
                b.LocalRotation = rot;
            }

            return s;
        }


        private Vector2 ParseVector2(string p)
        {
            return new Vector2(
                float.Parse(p.Split()[0], CultureInfo.InvariantCulture),
                float.Parse(p.Split()[1], CultureInfo.InvariantCulture));
        }

    }
}
